﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace Mbs.Threading
{
    [DebuggerDisplay("Value={value}")]
    public class AtomicInteger
    {
        private int value;

        public AtomicInteger(int initialValue)
        {
            value = initialValue;
        }

        public AtomicInteger():this(0)
        {
        }

        public int GetAndSet(int newValue)
        {
            for (; ; )
            {
                int current = value;
                if (CompareAndSet(current, newValue))
                    return current;
            }
        }

        public bool CompareAndSet(int expect, int update)
        {
            return Interlocked.CompareExchange(ref value, update, expect) == expect;
        }

        public int GetAndIncrement()
        {
            for (; ; )
            {
                int current = value;
                int next = current + 1;
                if (CompareAndSet(current, next))
                    return current;
            }
        }

        public int GetAndDecrement()
        {
            for (; ; )
            {
                int current = value;
                int next = current - 1;
                if (CompareAndSet(current, next))
                    return current;
            }
        }

        public int GetAndAdd(int delta)
        {
            for (; ; )
            {
                int current =value;
                int next = current + delta;
                if (CompareAndSet(current, next))
                    return current;
            }
        }

        private int IncrementAndGet()
        {
            for (; ; )
            {
                int current = value;
                int next = current + 1;
                if (CompareAndSet(current, next))
                    return next;
            }
        }

        private int DecrementAndGet()
        {
            for (; ; )
            {
                int current = value;
                int next = current - 1;
                if (CompareAndSet(current, next))
                    return next;
            }
        }

        private int AddAndGet(int delta)
        {
            for (; ; )
            {
                int current = value;
                int next = current + delta;
                if (CompareAndSet(current, next))
                    return next;
            }
        }

        private int MinusAndGet(int delta)
        {
            for (; ; )
            {
                int current = value;
                int next = current - delta;
                if (CompareAndSet(current, next))
                    return next;
            }
        }

        public override String ToString()
        {
            return Convert.ToString(value);
        }

        public static implicit operator int(AtomicInteger a)
        {
            return a.value;
        }

        public static implicit operator AtomicInteger(int i)
        {
            return new AtomicInteger(i);
        }

        public static AtomicInteger operator ++(AtomicInteger l)
        {
            l.IncrementAndGet();
            return l;
        }

        public static AtomicInteger operator --(AtomicInteger l)
        {
            l.DecrementAndGet();
            return l;
        }

        public static AtomicInteger operator +(AtomicInteger l, AtomicInteger r)
        {
            l.AddAndGet(r.value);
            return l;
        }

        public static AtomicInteger operator +(AtomicInteger l, int r)
        {
            l.AddAndGet(r);
            return l;
        }

        public static AtomicInteger operator -(AtomicInteger l, AtomicInteger r)
        {
            l.MinusAndGet(r.value);
            return l;
        }

        public static AtomicInteger operator -(AtomicInteger l, int r)
        {
            l.MinusAndGet(r);
            return l;
        }

       
        public static bool operator ==(AtomicInteger l, AtomicInteger r)
        {
            return l.value == r.value;
        }

        public static bool operator ==(AtomicInteger l, int r)
        {
            return l.value == r;
        }

        public static bool operator ==(int l, AtomicInteger r)
        {
            return l == r.value;
        }

        public static bool operator !=(AtomicInteger l, AtomicInteger r)
        {
            return l.value != r.value;
        }

        public static bool operator !=(AtomicInteger l, int r)
        {
            return l.value != r;
        }

        public static bool operator !=(int l, AtomicInteger r)
        {
            return l != r.value;
        }

        public static bool operator >(AtomicInteger l, AtomicInteger r)
        {
            return l.value > r.value;
        }

        public static bool operator >(AtomicInteger l, int r)
        {
            return l.value > r;
        }

        public static bool operator >(int l, AtomicInteger r)
        {
            return l > r.value;
        }

        public static bool operator >=(AtomicInteger l, AtomicInteger r)
        {
            return l.value >= r.value;
        }

        public static bool operator >=(AtomicInteger l, int r)
        {
            return l.value >= r;
        }

        public static bool operator >=(int l, AtomicInteger r)
        {
            return l >= r.value;
        }


        public static bool operator <=(AtomicInteger l, AtomicInteger r)
        {
            return l.value <= r.value;
        }

        public static bool operator <=(AtomicInteger l, int r)
        {
            return l.value <= r;
        }

        public static bool operator <=(int l, AtomicInteger r)
        {
            return l <= r.value;
        }

        public static bool operator <(AtomicInteger l, AtomicInteger r)
        {
            return l.value < r.value;
        }

        public static bool operator <(AtomicInteger l, int r)
        {
            return l.value < r;
        }

        public static bool operator <(int l, AtomicInteger r)
        {
            return l < r.value;
        }
    }
}
